package com.xyht.sca_s.student_manage_system.modules.rxRegistration.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.modules.advanceRegistration.entity.RxAdvanceRegistrationOrg;
import com.xyht.sca_s.student_manage_system.modules.advanceRegistration.mapper.RxAdvanceRegistrationOrgMapper;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.entity.RxRegistrationChargeCategory;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.entity.RxRegistrationChargeCategoryDetail;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.entity.req.RxRegistrationChargeCategoryDetailAddReq;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.entity.req.RxRegistrationChargeCategoryDetailReq;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.entity.resp.RxRegistrationChargeCategoryDetailResp;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.mapper.RxRegistrationChargeCategoryDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.mapper.RxRegistrationChargeCategoryMapper;
import com.xyht.sca_s.student_manage_system.modules.rxRegistration.service.RxRegistrationChargeCategoryDetailService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample.TASK_NAME_REGISTRATION_CHARGE_CATEGORY_DETAIL_IMPORT;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant.TASK_TYPE_REGISTRATION_CHARGE_CATEGORY_DETAIL_IMPORT;
import static com.xyht.sca_s.student_manage_system.modules.rxRegistration.constant.ChargeCategoryTypeConstant.CHARGE_CATEGORY_TYPE_DORMITORY;
import static com.xyht.sca_s.student_manage_system.modules.rxRegistration.constant.ChargeCategoryTypeConstant.CHARGE_CATEGORY_TYPE_MAJOR;
import static com.xyht.sca_s.student_manage_system.modules.student.constant.StudentInfoCommonConstant.PER_SHEET_NUM;

/**
 * <p>
 * 收费项子项 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2024-05-07
 */
@Service
public class RxRegistrationChargeCategoryDetailServiceImpl extends ServiceImpl<RxRegistrationChargeCategoryDetailMapper, RxRegistrationChargeCategoryDetail> implements RxRegistrationChargeCategoryDetailService {
    @Resource
    private RxRegistrationChargeCategoryDetailMapper rxRegistrationChargeCategoryDetailMapper;
    @Resource
    private RxRegistrationChargeCategoryMapper rxRegistrationChargeCategoryMapper;
    @Resource
    private RxAdvanceRegistrationOrgMapper rxAdvanceRegistrationOrgMapper;
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    PlatformTransactionManager transactionManager;

    @Override
    public ResponseResult addRxRegistrationChargeCategoryDetail(RxRegistrationChargeCategoryDetailReq categoryDetailReq) {
        if (isNullOrEmpty(categoryDetailReq.getParentId(), categoryDetailReq.getChargeCategoryName(),
                categoryDetailReq.getChargeCategoryPrice())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        if (categoryDetailReq.getChargeCategoryPrice().compareTo(BigDecimal.ZERO) < 0) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        RxRegistrationChargeCategory category = rxRegistrationChargeCategoryMapper.selectById(categoryDetailReq.getParentId());
        if (isNullOrEmpty(category)) {
            return CommonResult.failed(CommonCodeEnum.RX_REGISTRATION_CHARGE_CATEGORY_NOT_EXIST);
        }

        //判断专业是否存在
        if (category.getChargeCategoryType() == CHARGE_CATEGORY_TYPE_MAJOR) {
            List<RxAdvanceRegistrationOrg> orgList = rxAdvanceRegistrationOrgMapper.selectList(new LambdaQueryWrapper<RxAdvanceRegistrationOrg>()
                    .eq(RxAdvanceRegistrationOrg::getMajorName, categoryDetailReq.getChargeCategoryName()));
            if (orgList == null || orgList.size() == 0) {
                return CommonResult.failed(CommonCodeEnum.RX_REGISTRATION_CHARGE_CATEGORY_DETAIL_MAJOR_NOT_EXIST);
            }
        }

        //判断收费项是否存在(防止重复导入)
        List<RxRegistrationChargeCategoryDetail> detailList = rxRegistrationChargeCategoryDetailMapper.selectList(new LambdaQueryWrapper<RxRegistrationChargeCategoryDetail>()
                .eq(RxRegistrationChargeCategoryDetail::getParentId, categoryDetailReq.getParentId())
                .eq(RxRegistrationChargeCategoryDetail::getChargeCategoryName, categoryDetailReq.getChargeCategoryName()));
        if (detailList != null && detailList.size() > 0) {
            return CommonResult.failed(CommonCodeEnum.RX_REGISTRATION_CHARGE_CATEGORY_DETAIL_EXIST);
        }

        RxRegistrationChargeCategoryDetail addCharge = new RxRegistrationChargeCategoryDetail();
        addCharge.setParentId(categoryDetailReq.getParentId());
        addCharge.setChargeCategoryName(categoryDetailReq.getChargeCategoryName());
        addCharge.setChargeCategoryPrice(categoryDetailReq.getChargeCategoryPrice());
        rxRegistrationChargeCategoryDetailMapper.insert(addCharge);
        return CommonResult.success();
    }

    @Override
    @Async
    public Future<ResponseResult> batchAddRxRegistrationChargeCategoryDetail(RxRegistrationChargeCategoryDetailAddReq categoryDetailAddReq, String user_id) {
        if (isNullOrEmpty(categoryDetailAddReq.getParentId(), categoryDetailAddReq.getChargeCategoryDetailList())) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        if (categoryDetailAddReq.getChargeCategoryDetailList().size() == 0) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        RxRegistrationChargeCategory category = rxRegistrationChargeCategoryMapper.selectById(categoryDetailAddReq.getParentId());
        if (isNullOrEmpty(category)) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.RX_REGISTRATION_CHARGE_CATEGORY_NOT_EXIST));
        }

        //创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_REGISTRATION_CHARGE_CATEGORY_DETAIL_IMPORT);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_REGISTRATION_CHARGE_CATEGORY_DETAIL_IMPORT);
        smsImportTaskMapper.insert(smsImportTask);
        batchAddAdvanceRegistrationOrg(categoryDetailAddReq.getChargeCategoryDetailList(), smsImportTask.getId(), category);
        return new AsyncResult<>(CommonResult.success());
    }

    private void batchAddAdvanceRegistrationOrg(List<RxRegistrationChargeCategoryDetailReq> exportBatchReqs, String task_id, RxRegistrationChargeCategory parentCategory) {
        int OFFSET_ROW = 1;
        int task_status = TASK_STATUS_DONE;
        for (int i = 0; i < exportBatchReqs.size(); i++) {
            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);
            try {
                RxRegistrationChargeCategoryDetailReq categoryDetailReq = exportBatchReqs.get(i);
                if (isNullOrEmpty(categoryDetailReq.getChargeCategoryName(), categoryDetailReq.getChargeCategoryPrice())) {
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }

                //判断价格
                if (categoryDetailReq.getChargeCategoryPrice().compareTo(BigDecimal.ZERO) < 0) {
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_AMOUNT_LIST_NOT_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }

                if (parentCategory.getChargeCategoryType() == CHARGE_CATEGORY_TYPE_MAJOR) {
                    //判断专业是否存在
                    List<RxAdvanceRegistrationOrg> orgList = rxAdvanceRegistrationOrgMapper.selectList(new LambdaQueryWrapper<RxAdvanceRegistrationOrg>()
                            .eq(RxAdvanceRegistrationOrg::getMajorName, categoryDetailReq.getChargeCategoryName()));
                    if (orgList == null || orgList.size() == 0) {
                        transactionManager.rollback(status);
                        task_status = TASK_STATUS_ERR;
                        createTeacherImportTaskDetail(task_id, REASON_ORG_MAJOR_NOT_EXIST, (i + OFFSET_ROW) + "");
                        continue;
                    }
                }

                //判断收费项是否存在，存在就更新数据，不存在就新增数据
                List<RxRegistrationChargeCategoryDetail> detailList = rxRegistrationChargeCategoryDetailMapper.selectList(new LambdaQueryWrapper<RxRegistrationChargeCategoryDetail>()
                        .eq(RxRegistrationChargeCategoryDetail::getParentId, parentCategory.getId())
                        .eq(RxRegistrationChargeCategoryDetail::getChargeCategoryName, categoryDetailReq.getChargeCategoryName()));
                if (detailList != null && detailList.size() > 0) {
                    RxRegistrationChargeCategoryDetail updateCharge = detailList.get(0);
                    updateCharge.setChargeCategoryPrice(categoryDetailReq.getChargeCategoryPrice());
                    rxRegistrationChargeCategoryDetailMapper.updateById(updateCharge);
                } else {
                    RxRegistrationChargeCategoryDetail addCharge = new RxRegistrationChargeCategoryDetail();
                    addCharge.setParentId(parentCategory.getId());
                    addCharge.setChargeCategoryName(categoryDetailReq.getChargeCategoryName());
                    addCharge.setChargeCategoryPrice(categoryDetailReq.getChargeCategoryPrice());
                    rxRegistrationChargeCategoryDetailMapper.insert(addCharge);
                }
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                task_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(task_id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                }
            }
        }

        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setId(task_id);
        smsImportTask.setStatus(task_status);
        smsImportTaskMapper.updateById(smsImportTask);
    }

    private void createTeacherImportTaskDetail(String id, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(id);
        smsImportTaskDetail.setFailReason(reason);
        smsImportTaskDetail.setFailRow(row);
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }

    @Override
    public ResponseResult updateRxRegistrationChargeCategoryDetail(RxRegistrationChargeCategoryDetailReq categoryDetailReq) {
        if (isNullOrEmpty(categoryDetailReq.getId(), categoryDetailReq.getChargeCategoryPrice())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        if (categoryDetailReq.getChargeCategoryPrice().compareTo(BigDecimal.ZERO) < 0) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //只能修改价格
        RxRegistrationChargeCategoryDetail updatedCategoryDetail = new RxRegistrationChargeCategoryDetail();
        updatedCategoryDetail.setId(categoryDetailReq.getId());
        updatedCategoryDetail.setChargeCategoryPrice(categoryDetailReq.getChargeCategoryPrice());
        rxRegistrationChargeCategoryDetailMapper.updateById(updatedCategoryDetail);
        return CommonResult.success();
    }

    @Override
    public ResponseResult deleteRxRegistrationChargeCategoryDetail(RxRegistrationChargeCategoryDetailReq categoryDetailReq) {
        if (isNullOrEmpty(categoryDetailReq.getId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        rxRegistrationChargeCategoryDetailMapper.deleteById(categoryDetailReq.getId());
        return CommonResult.success();
    }

    @Override
    public Future<ResponseResult> exportRxRegistrationChargeCategoryDetail(Integer type,HttpServletResponse response) {
        try {
            List<RxAdvanceRegistrationOrg> list = rxAdvanceRegistrationOrgMapper.selectList(new LambdaQueryWrapper<>());
            //表头数据
            String[] header = {"收费项", "收费金额(单位：元)"};

            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("收费项模板表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = header[i - 1];
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    if (type == CHARGE_CATEGORY_TYPE_MAJOR){
                        for (int i = 0; i < range; i++) {
                            //创建一行
                            HSSFRow row1 = sheet.createRow(i + 1);
                            RxAdvanceRegistrationOrg advanceRegistrationOrg = list.get((PER_SHEET_NUM) * k + i);
                            row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                            row1.createCell(1).setCellValue(new HSSFRichTextString(advanceRegistrationOrg.getMajorName()));
                            row1.createCell(2).setCellValue(new HSSFRichTextString(0 + ""));
                        }
                    }else if (type == CHARGE_CATEGORY_TYPE_DORMITORY){
                        HSSFRow row1 = sheet.createRow(1);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(1 + ""));
                        row1.createCell(1).setCellValue(new HSSFRichTextString("四人间"));
                        row1.createCell(2).setCellValue(new HSSFRichTextString(600 + ""));

                        HSSFRow row2 = sheet.createRow(2);
                        row2.createCell(0).setCellValue(new HSSFRichTextString(2 + ""));
                        row2.createCell(1).setCellValue(new HSSFRichTextString("六人间"));
                        row2.createCell(2).setCellValue(new HSSFRichTextString(400 + ""));
                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("收费项模板表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("收费项模板表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
//            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);
            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return new AsyncResult<>(CommonResult.success());
    }

    @Override
    public ResponseResult getRxRegistrationChargeCategoryDetailList(String searchStr, String chargeCategoryId, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<RxRegistrationChargeCategoryDetail> queryWrapper = new LambdaQueryWrapper<>();
        if (!isNullOrEmpty(searchStr)) {
            queryWrapper.like(RxRegistrationChargeCategoryDetail::getChargeCategoryName, searchStr);
        }
        if (!isNullOrEmpty(chargeCategoryId)) {
            queryWrapper.eq(RxRegistrationChargeCategoryDetail::getParentId, chargeCategoryId);
        }
        Page<RxRegistrationChargeCategoryDetail> page = new Page<>(pageNum, pageSize);
        rxRegistrationChargeCategoryDetailMapper.selectPage(page, queryWrapper);

        List<RxRegistrationChargeCategoryDetailResp> list = page.getRecords()
                .stream()
                .map(chargeCategoryDetail -> {
                    RxRegistrationChargeCategoryDetailResp chargeCategoryDetailResp = new RxRegistrationChargeCategoryDetailResp();
                    BeanUtils.copyProperties(chargeCategoryDetail, chargeCategoryDetailResp);
                    return chargeCategoryDetailResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(list, total);
    }
}
